#ifndef FILESYSTEM_H
#define FILESYSTEM_H

#include <disk.h>
#include <file.h>
#include <map>
#include <vector>
#include <config.h>
#include <queue>

using std::map;
using std::vector;
using std::string;

class FileSystem
{
public:
    FileSystem();

    FileSystem(Disk *disk) {
        disk_ = disk;
        opening_path_ = "/";
        root_dir_item_block_ = disk_->GetFatSize() / BLOCK_SIZE + 1;
        OpenDir("/");
    }

    /**
     * @brief 划分盘块作为目录项
     */
    void InitDirectoryItem();

    /**
     * @brief DeleteFile
     * @param f
     * @return
     */
    bool DeleteFile(File file);

    /**
     * @brief NewFile
     * @param file
     * @return
     */
    int NewFile(File &file);

    /**
     * @brief RenameFile
     * @param file
     * @return
     */
    bool RenameFile(File &file);

    /**
     * @brief UpdateFile
     * @param file
     * @return
     */
    bool UpdateFile(File &file);

    /**
     * @brief 将磁盘进行格式化
     */
    void Format();

    /**
     * @brief 获取指定盘块内的所有目录项
     * @param block_id
     * @return
     */
    vector<File> GetDirItemInBlock(int block_id );

    /**
     * @brief 获取指定盘块内的目录项
     * @return
     */
    vector<File> GetRootDirItem();

    /**
     * @brief 向块中添加目录项
     * @return
     */
    int AddDirItemToBlock(int block_id, File dir_item);

    /**
     * @brief 同步目录项至磁盘
     * @param block_id
     * @param dir_items
     * @return
     */
    bool SyncDirItemToDisk(int block_id, vector<File> *dir_items);

    /**
     * @brief 获取根目录内的目录项
     * @return
     */
    int GetRootDirItemBlock() {
        return root_dir_item_block_;
    }

    /**
     * @brief 获取盘块项内的非空目录项数量
     * @param block_id
     * @return
     */
    int GetNumOfDirItemInBlock(int block_id);

    /**
     * @brief 新建目录
     * @param file
     * @return
     */
    int NewDir(File file);

    /**
     * @brief 初始化文件 map
     */
    void InitFileMap();
    
    /**
     * @brief 是否存在目录
     * @param name
     * @return 
     */
    bool ExistDir(string name);
    
    /**
     * @brief 指定目录下是否有空目录像
     * @param path
     * @return 空目录项的下标 没有则返回-1
     */
    int GetEmptyDirItemIndex(string path);
    
    /**
     * @brief 指定文件是否存在
     * @param file
     * @return 
     */
    bool ExistFile(File file);
    
    /**
     * @brief 从目录的目录项中寻找指定名字的文件下标
     * @param name
     * @return 
     */
    int FindIndexInDirByName(string path, string name);
    
    /**
     * @brief ReadFile
     * @param file
     * @return 
     */
    string ReadFile(File &file);
    
    /**
     * @brief WriteFile
     * @param file
     * @return 
     */
    bool WriteFile(File &file);
    
    /**
     * @brief Flush
     */
    void Flush();
    
    /**
     * @brief OpenFile
     * @param path_name
     * @return 
     */
    bool OpenFile(string path_name);
    
    /**
     * @brief OpenDir
     * @param path
     * @return 
     */
    bool OpenDir(string path);
    
    /**
     * @brief GetDirItems
     * @param path
     * @return 
     */
    std::vector<File>* GetDirItems(string path);
    
    /**
     * @brief GetOpeningFile
     * @return 
     */
    File* GetOpeningFile() {
        return opening_file_;
    }
    
    /**
     * @brief GetOpeningPath
     * @return 
     */
    string GetOpeningPath() {
        return opening_path_;
    }
    
    /**
     * @brief GetOpeningPathDirItems
     * @return 
     */
    vector<File>* GetOpeningPathDirItems() {
        return GetDirItems(opening_path_);
    }
    
    /**
     * @brief ReadOpeningFile
     * @return 
     */
    bool ReadOpeningFile();
    
    /**
     * @brief Get Disk Used Ratio
     * @return 
     */
    double GetDiskUsedRatio() {
        return disk_->GetDiskUsedRatio();
    }
    
    /**
     * @brief GetFileDirItemPtr
     * @param path_name
     * @return 
     */
    File* GetFileDirItemPtr(string path_name);
    
    void CloseOpeningFile();
    
    string GetAllCodesInDisk();
    
    void LoadFileContent(File* file);
    
    bool MoveFileOrDir(File* file, string new_path);
    
    bool ModifyAllPathInDir(File* dir, string path);

private:
    Disk* disk_;

    File *opening_file_;
    
    string opening_path_;

    map<string, vector<File>> file_map_;

    int dir_item_start_;

    int dir_item_end_;

    int root_dir_item_block_;
};

#endif // FILESYSTEM_H
